/*
 * TODO language 
 * Copyright (c) 2010 TODO Team
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <iostream>
#include <cstdarg>
#include <cstdlib>
#include <sstream>
#include "types.h"
#include "API.h"

namespace todo {
	
/**
 * Create a list of Type* pointers
 */
Type** TypeList(unsigned int num, ...)
{
	va_list argptr;
	Type** types = new Type*[num];
	
	va_start(argptr, num);
	
	for (unsigned int i = 0; i < num; ++i) {
		types[i] = typeman.get_type(va_arg(argptr, const char*));
	}	
	
	va_end(argptr);
	
	return types;
}

/**
 * Formatter
 */
void vtsprintf(std::string& outstr, const char* format, va_list ap)
{
	char* chr = const_cast<char*>(format);

	if (!chr) {
		return;
	}
	
	while (*chr) {
		// Check for escape %%
		if (*chr != '%' || *++chr == '%') {
			outstr += *chr++;
			continue;
		}
				
		switch (*chr) {
			// todo_vector*
			case 'a': {
				todo_vector* vector = va_arg(ap, todo_vector*);
				unsigned int vector_size = vector->size();
				Value* ret;
				
				for (unsigned int i = 0; i < vector_size; ++i) {
					ret = (*vector)[i]->type->call_method("toString", (*vector)[i], NULL);
					outstr += STR_V(ret);
					if (i+1 != vector_size) {
						outstr += ", ";
					}
					ret->type->dealloc(ret);
				}
				}
				break;
			// todo_map*
			case 'm': {
				todo_map* map = va_arg(ap, todo_map*);
				todo_map::iterator it;
				Value* ret;
				
				for (it = map->begin(); it != map->end();) {
					outstr += it->first + ": ";
					ret = it->second->type->call_method("toString", it->second, NULL);
					outstr += STR_V(ret);
					ret->type->dealloc(ret);
					
					++it;
					if (it != map->end()) {
						outstr += ", ";
					}
				}
				}
				break;
			// std::string*
			case 'S':
				outstr += *va_arg(ap, std::string*);
				break;
			// Value*
			case 'v': {
				Value* tmp_value = va_arg(ap, Value*);
				Value* ret;
				
				ret = tmp_value->type->call_method("toString", tmp_value, NULL);
				outstr += STR_V(ret);
				ret->type->dealloc(ret);				
				}
				break;
			// const char*
			case 's':
				outstr += va_arg(ap, const char*);				
				break;
			// long*
			case 'd':
			case 'l': {
				std::stringstream ss;
				
				ss << *va_arg(ap, long*);
				outstr += ss.str();
				}
				break;
			// double*
			case 'f': {
				std::stringstream ss;
				
				ss << *va_arg(ap, double*);
				outstr += ss.str();
				}
				break;
		}
		chr++;
	}
}

/**
 * Our sprintf
 */
void tsprintf(std::string& outstr, const char* format, ...)
{
	va_list args;

	va_start(args, format);
	
	vtsprintf(outstr, format, args);
	
	va_end(args);	
}

/**
 * Our printf
 */
void tprintf(const char* format, ...)
{
	std::string out;
	va_list args;
	
	va_start(args, format);
	
	vtsprintf(out, format, args);
	
	std::cout << out;
	
	va_end(args);
}

/**
 * Our printf
 */
void tprintlnf(const char* format, ...)
{
	std::string out;
	va_list args;
	
	va_start(args, format);
	
	vtsprintf(out, format, args);
	
	std::cout << out << std::endl;
	
	va_end(args);
}

} // todo
